// RFC3550 6.4.1 SR: Sender Report RTCP Packet

#include "rtp-internal.h"
#include "rtp-util.h"

void rtcp_sr_unpack(struct rtp_context *ctx, const rtcp_header_t *header, const uint8_t *ptr, size_t bytes)
{
    uint32_t i;
    rtcp_sr_t *sr;
    rtcp_rb_t *rb;
    struct rtcp_msg_t msg;
    struct rtp_member *sender;

    assert(24 == sizeof(rtcp_sr_t));
    assert(24 == sizeof(rtcp_rb_t));
    if (bytes < 24 /*sizeof(rtcp_sr_t)*/ + header->rc * 24 /*sizeof(rtcp_rb_t)*/) {
        assert(0);
        return;
    }
    msg.ssrc = nbo_r32(ptr);
    msg.type = RTCP_RR;

    sender = rtp_sender_fetch(ctx, msg.ssrc);
    if (!sender)
        return; // error

    assert(sender != ctx->self);
    assert(sender->rtcp_sr.ssrc == msg.ssrc);
    // assert(sender->rtcp_rb.ssrc == msg.ssrc);
    sender->rtcp_clock = rtpclock();

    // update sender information
    sr = &sender->rtcp_sr;
    sr->ntpmsw = nbo_r32(ptr + 4);
    sr->ntplsw = nbo_r32(ptr + 8);
    sr->rtpts = nbo_r32(ptr + 12);
    sr->spc = nbo_r32(ptr + 16);
    sr->soc = nbo_r32(ptr + 20);

    ptr += 24;
    // report block
    for (i = 0; i < header->rc; i++, ptr += 24 /*sizeof(rtcp_rb_t)*/) {
        msg.u.sr.ssrc = nbo_r32(ptr);
        // if(msg.u.rr.ssrc != ctx->self->ssrc)
        //	continue; // ignore
        // rb = &sender->rtcp_rb;

        rb = &msg.u.sr;
        rb->fraction = ptr[4];
        rb->cumulative = (((uint32_t)ptr[5]) << 16) | (((uint32_t)ptr[6]) << 8) | ptr[7];
        rb->exthsn = nbo_r32(ptr + 8);
        rb->jitter = nbo_r32(ptr + 12);
        rb->lsr = nbo_r32(ptr + 16);
        rb->dlsr = nbo_r32(ptr + 20);

        ctx->handler.on_rtcp(ctx->cbparam, &msg);
    }
}

int rtcp_sr_pack(struct rtp_context *ctx, uint8_t *ptr, int bytes)
{
    uint32_t i, timestamp;
    uint64_t ntp;
    rtcp_header_t header;

    assert(24 == sizeof(rtcp_sr_t));
    assert(24 == sizeof(rtcp_rb_t));
    assert(rtp_member_list_count(ctx->senders) < 32);
    header.v = 2;
    header.p = 0;
    header.pt = RTCP_SR;
    header.rc = MIN(31, rtp_member_list_count(ctx->senders));
    header.length = (24 /*sizeof(rtcp_sr_t)*/ + header.rc * 24 /*sizeof(rtcp_rb_t)*/) /
                    4; // see 6.4.1 SR: Sender Report RTCP Packet

    if ((uint32_t)bytes < (header.length + 1) * 4)
        return (header.length + 1) * 4;

    nbo_write_rtcp_header(ptr, &header);

    // RFC3550 6.4.1 SR: Sender Report RTCP Packet (p32)
    // Note that in most cases this timestamp will not be equal to the RTP
    // timestamp in any adjacent data packet. Rather, it must be calculated from the corresponding
    // NTP timestamp using the relationship between the RTP timestamp counter and real time as
    // maintained by periodically checking the wallclock time at a sampling instant.
    ntp = rtpclock();
    if (0 == ctx->self->rtp_packets)
        ctx->self->rtp_clock = ntp;
    timestamp = (uint32_t)((ntp - ctx->self->rtp_clock) * ctx->frequence / 1000000) + ctx->self->rtp_timestamp;

    ntp = clock2ntp(ntp);
    nbo_w32(ptr + 4, ctx->self->ssrc);
    nbo_w32(ptr + 8, (uint32_t)(ntp >> 32));
    nbo_w32(ptr + 12, (uint32_t)(ntp & 0xFFFFFFFF));
    nbo_w32(ptr + 16, timestamp);
    nbo_w32(ptr + 20, ctx->self->rtp_packets);         // send packets
    nbo_w32(ptr + 24, (uint32_t)ctx->self->rtp_bytes); // send bytes

    ptr += 28;
    // report block
    for (i = 0; i < header.rc; i++) {
        struct rtp_member *sender;

        sender = rtp_member_list_get(ctx->senders, i);
        if (0 == sender->rtp_packets || sender->ssrc == ctx->self->ssrc)
            continue; // don't receive any packet

        ptr += rtcp_report_block(sender, ptr, 24);
    }

    return (header.length + 1) * 4;
}

int rtcp_report_block(struct rtp_member *sender, uint8_t *ptr, int bytes)
{
    uint64_t delay;
    int lost_interval;
    int lost;
    uint32_t fraction;
    uint32_t expected, extseq;
    uint32_t expected_interval;
    uint32_t received_interval;
    uint32_t lsr, dlsr;

    if (bytes < 24)
        return 0;

    extseq = sender->rtp_seq_cycles + sender->rtp_seq; // 32-bits sequence number
    assert(extseq >= sender->rtp_seq_base);
    expected = extseq - sender->rtp_seq_base + 1;
    expected_interval = expected - sender->rtp_expected0;
    received_interval = sender->rtp_packets - sender->rtp_packets0;
    lost_interval = (int)(expected_interval - received_interval);
    if (lost_interval < 0 || 0 == expected_interval)
        fraction = 0;
    else
        fraction = (lost_interval << 8) / expected_interval;

    lost = expected - sender->rtp_packets;
    if (lost > 0x007FFFFF) {
        lost = 0x007FFFFF;
    } else if (lost < 0) {
        // 'Clamp' this loss number to a 24-bit signed value:
        // live555 RTCP.cpp RTCPInstance::enqueueReportBlock line:799
        lost = 0;
    }

    delay = rtpclock() - sender->rtcp_clock; // now - Last SR time
    lsr = ((sender->rtcp_sr.ntpmsw & 0xFFFF) << 16) | ((sender->rtcp_sr.ntplsw >> 16) & 0xFFFF);
    // in units of 1/65536 seconds
    // 65536/1000000 == 1024/15625
    dlsr = (uint32_t)(delay / 1000000.0f * 65536);

    nbo_w32(ptr, sender->ssrc);
    ptr[4] = (unsigned char)fraction;
    ptr[5] = (unsigned char)((lost >> 16) & 0xFF);
    ptr[6] = (unsigned char)((lost >> 8) & 0xFF);
    ptr[7] = (unsigned char)(lost & 0xFF);
    nbo_w32(ptr + 8, extseq);
    nbo_w32(ptr + 12, (uint32_t)sender->jitter);
    nbo_w32(ptr + 16, lsr);
    nbo_w32(ptr + 20, 0 == lsr ? 0 : dlsr);

    sender->rtp_expected0 = expected; // update source prior data
    sender->rtp_packets0 = sender->rtp_packets;

    return 24; /*sizeof(rtcp_rb_t)*/
}
